﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace PPSkin
{
    [Description("平面形式checkbox，可自定义颜色"), DefaultEvent("CheckedChanged")]
    public partial class PPCheckBox : UserControl
    {
        #region 属性定义

        private bool check = false;
        private int radius = 30;
        private int buttonRadius = 30;
        private int xoffset = 0;
        private int yoffset = 0;
        private Color checkedBaseColor = Color.DodgerBlue;
        private Color unCheckedBaseColor = Color.Gray;
        private Color buttonColor = Color.White;
        private string checkedText = "";
        private string uncheckedText = "";
        private Color checkedColor = Color.Green;
        private Color uncheckedColor = Color.Red;
        private Enums.RoundStyle roundStyle = Enums.RoundStyle.All;

        private Bitmap checkedImage = null;
        private Bitmap unCheckedImage = null;
        private Size imageSize = new Size(15, 15);

        private PPAnimation anim;//自定义动画组件
        private bool useAnimation = false;
        private int buttonRectx = 0;
        private int buttonRecty = 0;
        private int buttonRectw = 0;
        private int buttonRecth = 0;

        [Description("选中显示文本"), Category("PPSkin")]
        public string CheckedText
        {
            get { return checkedText; }
            set
            {
                checkedText = value;
                this.Invalidate();
            }
        }

        [Description("未选中显示文本"), Category("PPSkin")]
        public string UnCheckedText
        {
            get { return uncheckedText; }
            set
            {
                uncheckedText = value;
                this.Invalidate();
            }
        }

        [Description("选中显示文本颜色"), Category("PPSkin")]
        public Color CheckedColor
        {
            get { return checkedColor; }
            set
            {
                checkedColor = value;

                this.Invalidate();
            }
        }

        [Description("未选中显示文本颜色"), Category("PPSkin")]
        public Color UnCheckedColor
        {
            get { return uncheckedColor; }
            set
            {
                uncheckedColor = value;
                this.Invalidate();
            }
        }

        [Description("是否选中"), Category("PPSkin")]
        public bool Checked
        {
            get
            {
                return check;
            }
            set
            {
                bool m = check;
                check = value;
                if (m != check)
                {
                    if (CheckedChanged != null)
                    {
                        CheckedChanged(this, new EventArgs());
                    }
                }

                if (check)
                {
                    if (useAnimation)
                    {
                        if (!DesignMode)
                        {
                            Dictionary<string, float> dic = new Dictionary<string, float>();
                            dic.Add("buttonRectX", this.Width - this.Height + 4);
                            dic.Add("buttonRectY", 4);
                            dic.Add("buttonRectWidth", this.Height - 8);
                            dic.Add("buttonRectHeight", this.Height - 8);
                            dic.Add("BaseColor", checkedBaseColor.ToArgb());
                            anim.AnimationControl(dic, 200);
                        }
                        else
                        {
                            buttonRectx = this.Width - this.Height + 4;
                            buttonRecty = 4;
                            buttonRectw = this.Height - 8;
                            buttonRecth = this.Height - 8;
                            BaseColor = CheckedBaseColor;
                        }
                    }
                    else
                    {
                        buttonRectx = this.Width - this.Height + 4;
                        buttonRecty = 4;
                        buttonRectw = this.Height - 8;
                        buttonRecth = this.Height - 8;
                        BaseColor = checkedBaseColor;
                    }
                }
                else
                {
                    if (useAnimation)
                    {
                        if (!DesignMode)
                        {
                            Dictionary<string, float> dic = new Dictionary<string, float>();
                            dic.Add("buttonRectX", 4);
                            dic.Add("buttonRectY", 4);
                            dic.Add("buttonRectWidth", this.Height - 8);
                            dic.Add("buttonRectHeight", this.Height - 8);
                            dic.Add("BaseColor", unCheckedBaseColor.ToArgb());
                            anim.AnimationControl(dic, 200);
                        }
                        else
                        {
                            buttonRectx = 4;
                            buttonRecty = 4;
                            buttonRectw = this.Height - 8;
                            buttonRecth = this.Height - 8;
                            BaseColor = unCheckedBaseColor;
                        }
                    }
                    else
                    {
                        buttonRectx = 4;
                        buttonRecty = 4;
                        buttonRectw = this.Height - 8;
                        buttonRecth = this.Height - 8;
                        BaseColor= unCheckedBaseColor;
                    }
                }
                this.Invalidate();
            }
        }

        [Description("圆角直径"), Category("PPSkin")]
        public int Radius
        {
            get { return radius; }
            set
            {
                //if (value != 0 && value < 8)
                //    return;
                radius = value;
                //this.Region = new Region(PaintHelper.CreateRound(new Rectangle(0, 0, this.Width, this.Height), radius));
                this.Invalidate();
            }
        }

        [Description("中间按钮的圆角直径"), Category("PPSkin")]
        public int ButtonRadius
        {
            get { return buttonRadius; }
            set
            {
                buttonRadius = value;
                this.Invalidate();
            }
        }

        [Description("圆角类型"), Category("PPSkin")]
        public Enums.RoundStyle RoundStyle
        {
            get { return roundStyle; }
            set
            {
                roundStyle = value;
                this.Invalidate();
            }
        }

        [Description("文本x位置偏移"), Category("PPSkin")]
        public int Xoffset
        {
            get { return xoffset; }
            set
            {
                xoffset = value;
                this.Invalidate();
            }
        }

        [Description("文本y位置偏移"), Category("PPSkin")]
        public int Yoffset
        {
            get { return yoffset; }
            set
            {
                yoffset = value;
                this.Invalidate();
            }
        }

        [Description("选中背景色"), Category("PPSkin")]
        public Color CheckedBaseColor
        {
            get { return checkedBaseColor; }
            set
            {
                checkedBaseColor = value;
                if (Checked)
                {
                    BaseColor = checkedBaseColor;
                }
                this.Invalidate();
            }
        }

        [Description("未选择背景色"), Category("PPSkin")]
        public Color UnCheckedBaseColor
        {
            get { return unCheckedBaseColor; }
            set
            {
                unCheckedBaseColor = value;
                if (!Checked)
                {
                    BaseColor = unCheckedBaseColor;
                }
                this.Invalidate();
            }
        }

        [Browsable(false)]
        [Description("背景色，一般不手动修改，用于动画"), Category("PPSkin")]
        public Color BaseColor { get; set; }

        [Description("正常文字色"), Category("PPSkin")]
        public Color ButtonColor
        {
            get { return buttonColor; }
            set
            {
                buttonColor = value;
                this.Invalidate();
            }
        }

        [Description("选中时的图片"), Category("PPSkin")]
        public Bitmap CheckedImage
        {
            get { return checkedImage; }
            set
            {
                checkedImage = value;
                this.Invalidate();
            }
        }

        [Description("未选中时的图片"), Category("PPSkin")]
        public Bitmap UnCheckedImage
        {
            get { return unCheckedImage; }
            set
            {
                unCheckedImage = value;
                this.Invalidate();
            }
        }

        [Description("图片大小"), Category("PPSkin")]
        public Size ImageSize
        {
            get { return imageSize; }
            set
            {
                imageSize = value;
                this.Invalidate();
            }
        }

        [Description("是否启用动画"), Category("PPSkin")]
        public bool UseAnimation
        {
            get { return useAnimation; }
            set
            {
                useAnimation = value;
            }
        }

        [Browsable(false)]
        [Description("中心按钮的x坐标，用于动画，不可手动修改"), Category("PPSkin.动画")]
        public int buttonRectX
        {
            get { return buttonRectx; }
            set { buttonRectx = value; this.Invalidate(); }
        }

        [Browsable(false)]
        [Description("中心按钮的y坐标，用于动画，不可手动修改"), Category("PPSkin.动画")]
        public int buttonRectY
        {
            get { return buttonRecty; }
            set { buttonRecty = value; this.Invalidate(); }
        }

        [Browsable(false)]
        [Description("中心按钮的宽，用于动画，不可手动修改"), Category("PPSkin.动画")]
        public int buttonRectWidth
        {
            get { return buttonRectw; }
            set { buttonRectw = value; this.Invalidate(); }
        }

        [Browsable(false)]
        [Description("中心按钮的高，用于动画，不可手动修改"), Category("PPSkin.动画")]
        public int buttonRectHeight
        {
            get { return buttonRecth; }
            set { buttonRecth = value; this.Invalidate(); }
        }

        public event EventHandler CheckedChanged;

        public Enums.DrawMode TextDrawMode { get; set; } = Enums.DrawMode.Anti;


        #endregion 属性定义

        /// <summary>
        /// 自定义绘制checkbox
        /// </summary>
        public PPCheckBox()
        {
            InitializeComponent();
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.DoubleBuffer, true);
            this.SetStyle(ControlStyles.ResizeRedraw, true);
            this.SetStyle(ControlStyles.Selectable, true);
            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            this.SetStyle(ControlStyles.UserPaint, true);

            this.Size = new Size(50, 25);
            //this.Region = new Region(PaintHelper.CreateRound(new Rectangle(0, 0, this.Width, this.Height), radius));

            anim = new PPAnimation(this);
            anim.AnimationType = AnimationType.EaseOut;

            buttonRectX = 4;
            buttonRectY = 4;
            buttonRectWidth = this.Height - 8;
            buttonRectHeight = this.Height - 8;
            BaseColor = Checked ? CheckedBaseColor : UnCheckedBaseColor;
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            int width = this.Width;
            int height = this.Height;

            Graphics g = e.Graphics;
            g.SmoothingMode = SmoothingMode.HighQuality;
            g.TextRenderingHint = TextDrawMode == Enums.DrawMode.Anti ? System.Drawing.Text.TextRenderingHint.AntiAlias : System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
            Brush brush = new SolidBrush(BaseColor);// check ? new SolidBrush(checkedBaseColor) : new SolidBrush(unCheckedBaseColor);
            Brush brush2 = new SolidBrush(buttonColor);
            Brush brushCheck = new SolidBrush(checkedColor);
            Brush brushUncheck = new SolidBrush(uncheckedColor);
            Pen penBack = new Pen(this.BackColor);

            g.Clear(this.BackColor);
            if (radius == 0)
            {
                g.SmoothingMode = SmoothingMode.Default;
            }
            GraphicsPath path = PaintHelper.CreatePath(new Rectangle(0, 0, this.Width, this.Height), radius,roundStyle);
            g.FillPath(brush, path);
            GraphicsPath path2;

            if (buttonRadius == 0)
                g.SmoothingMode = SmoothingMode.Default;
            else
                g.SmoothingMode = SmoothingMode.HighQuality;
            if (Checked)
            {
                if (checkedImage != null)
                {
                    g.DrawImage(checkedImage, new Rectangle(xoffset, yoffset, imageSize.Width, imageSize.Height));
                }
                else
                {
                    //int mradius = radius == 0 ? 8 : radius;
                    path2 = PaintHelper.CreatePath(new Rectangle(new Point(buttonRectX, buttonRectY), new Size(buttonRectWidth, buttonRectHeight)), buttonRadius);
                    Size fontsize = TextRenderer.MeasureText(checkedText, this.Font);
                    Rectangle rect = new Rectangle(0, 0, this.Width - height + 8, this.Height);
                    g.DrawString(checkedText, this.Font, brushCheck, new Point(rect.Width / 2 - fontsize.Width / 2 + 2 + xoffset, rect.Height / 2 - fontsize.Height / 2 + yoffset));
                    
                    g.FillPath(brush2, path2);
                    g.DrawPath(penBack, path);
                    path2.Dispose();
                }
            }
            else
            {
                if (unCheckedImage != null)
                {
                    g.DrawImage(unCheckedImage, new Rectangle(xoffset, yoffset, imageSize.Width, imageSize.Height));
                }
                else
                {
                    //int mradius = radius == 0 ? 8 : radius;
                    path2 = PaintHelper.CreatePath(new Rectangle(new Point(buttonRectX, buttonRectY), new Size(buttonRectWidth, buttonRectHeight)), buttonRadius);
                    Size fontsize = TextRenderer.MeasureText(uncheckedText, this.Font);
                    Rectangle rect = new Rectangle(height - 4, 0, this.Width - height + 4, this.Height);
                    g.DrawString(uncheckedText, this.Font, brushUncheck, new Point(rect.Left + rect.Width / 2 - fontsize.Width / 2 + 2 + xoffset, rect.Height / 2 - fontsize.Height / 2 + yoffset));
                    g.FillPath(brush2, path2);
                    g.DrawPath(penBack, path);
                    path2.Dispose();
                }
            }

            brush.Dispose();
            brush2.Dispose();
            brushCheck.Dispose();
            brushUncheck.Dispose();
            penBack.Dispose();
            path.Dispose();
        }

        protected override void OnClick(EventArgs e)
        {
            Checked = !Checked;
            
            base.OnClick(e);
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            if (this.Height > this.Width)
            {
                this.Width = this.Height;
            }
            if (radius > Math.Min(this.Width, this.Height))
            {
                radius = Math.Min(this.Width, this.Height);
            }

            if (check)
            {
                buttonRectX = this.Width - this.Height + 4;
                buttonRectY = 4;
                buttonRectWidth = this.Height - 8;
                buttonRectHeight = this.Height - 8;
            }
            else
            {
                buttonRectX = 4;
                buttonRectY = 4;
                buttonRectWidth = this.Height - 8;
                buttonRectHeight = this.Height - 8;
            }
            //this.Region = new Region(PaintHelper.CreatePath(new Rectangle(0, 0, this.Width, this.Height), radius));
        }
    }
}